package Thread;

// 模拟实现一个阻塞队列
// 基于数组的方式来实现队列
// 提供两个核心方法
// 1、put 入队列
// 2、take 出队列
class MyBlockingQueue {
    // 假定元素的 1000个
    private int[] items = new int[1000];
    //队首
    private int head = 0;
    // 队尾
    private int tail = 0;
    // 元素个数
    volatile private int size = 0;

    // 入队列
    public void put(int value) throws InterruptedException {
        synchronized (this) {
            if (items.length == size) {
                // 队列已满，无法插入，等待
                this.wait(); // 等待 2
            }

            items[tail] = value;
            tail++;
            if (tail == items.length) {
                tail = 0;
            }
            size++;
            // 无人等待调用 notify 没有副作用
            this.notify(); // 通知 1
        }
    }

    // 出队列
    public Integer take() throws InterruptedException {
        int a = 0;
        synchronized (this) {
            // 队列为空，就等待
            if (size == 0) {
                this.wait(); // 等待 1
            }

            a = items[head];
            head++;
            if (head == items.length) {
                head = 0;
            }
            size--;

            this.notify(); // 通知 2
        }
        return a;
    }
}

public class Demo20 {
    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue();
        Thread customer = new Thread(() -> {
           while (true) {
               int value = 0;

               try {
                   value = queue.take();
                   System.out.println("消费：" + value);
                   Thread.sleep(500);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        customer.start();

        Thread producer = new Thread(() -> {
            int value = 0;
            while (true) {
                try {
                    queue.put(value);
                    System.out.println("生产：" + value);
                    value++;


                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        producer.start();

    }
}
